/*->c.cross */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <locale.h>

#include "h.os"
#include "h.wimp"
#include "h.sprite"
#include "h.wimpt"
#include "h.bbc"
#include "h.akbd"
#include "h.werr"
#include "h.swis"
#include "h.font"

#include "h.drawlevel0"


#include "h.def"

#include "h.wos"
#include "h.ram"
#include "h.mym"
#include "h.file"
#include "h.dc"
#include "h.sp"
#include "h.vm"
#include "h.key"

#include "h.main"

#include "h.drawlib"

#include "h.cross"



/******************************************************************************/
#define MAXX     128
#define MAXY     128
#define EXT      640
#define WIDTH    25

#define CHWIDTH    16
#define CHWIDTH2   28

#define CHHEIGHT   32

#define VERTMARGIN  8
#define VERTSHIFT   8

#define HORIZMARGIN 8
#define HORIZSHIFT  12


#define RED       11
#define BLACK     7
#define WHITE     0
#define BLUE      15
#define LIGHTGREY 1
#define GREY      2


#define CHARST  0
#define HILITE  1
#define BLOCK   2

#define BLOCKX  0x4
#define BLOCKY  0x8

#define STMASK  0x3

#define XMASK   0x40
#define YMASK   0x80


char    griddata[MAXX][MAXY];
char    gridstate[MAXX][MAXY];


int      nsol;                      /* number of  solutions          */
int      maxsol;
int      solwidth=1;                /* number of  words per solution */
int      solheight=32;              /* height of  solution in window */
int      solxwidth;
buffer * sbuffer;                   /* buffer for solutions          */

int cursorcolour;
int zonecolour;
int textcolour;
int innercolour;
int outercolour;
int iconfront;
int iconback;
int xdraftcolour;
int xrealcolour;


int maxx=16;
int maxy=16;
int meshx;
int meshy;
int cursx;
int cursy;
int lcursx;
int lcursy;

int reflag=0;

int zx0;                            /* coords of zone */
int zy0;
int zx1;
int zy1;


cluestruct cluestr[MAXCLUE];      /* big list of things to solve */


void wzone(void);

int scroll_left(void);
int scroll_right(void);
int scroll_up(void);
int scroll_down(void);

void writesolution(int y);
void blanksolutions(void);


int xext=EXT;
int yext=-EXT;

int saveupper;

int draftfill;


int cluex0;
int cluex1;
int cluey0;
int cluey1;

int barthickness;


/*****************************************************************************/



void opencross(wimp_openstr * openstr)
{
 int x;
 int y;
 int h;
 int xm0;
 int ym1;
 wimp_wstate wst;

 x=openstr->box.x0;
 y=openstr->box.y1;
 h=openstr->behind;

 if(h==-2)
 {
  wimp_get_wind_state(whandle[CROSS],&wst);
  wst.o.behind=-2;
  wimp_open_wind(&wst.o);
  getw(whandle[CROSS]);
  h=bhandle;
 }
 else getw(whandle[CROSS]);

 xm0=x0;
 ym1=y1;

 getw(whandle[CROSS3]);
 open(whandle[CROSS3],x+(x0-xm0),y-(ym1-y1)-y1+y0,x+(x0-xm0)-x0+x1,
                                                    y-(ym1-y1),scx,scy,h);

 getw(whandle[CROSS2]);
 open(whandle[CROSS2],x+(x0-xm0),y-(ym1-y1)-y1+y0,x+(x0-xm0)-x0+x1,y
                                        -(ym1-y1),scx,scy,whandle[CROSS3]);
                                                                                 getw(whandle[CROSS]);

 open(whandle[CROSS],x,y-y1+y0,x-x0+x1,y,scx,scy,whandle[CROSS2]);
}




/****************************************************************************/


void shadedsquare(int x,int y)
{
 int i;
 int w;
 int h;

 w=meshx;
 h=meshy;

 wimp_setcolour(BLACK);
 bbc_rectanglefill(x,y,meshx,-meshy);

 x+=2;
 y-=4;
 w-=4;
 h-=6;

 wimp_setcolour(4);

 for(i=0;i<4;i+=deltay)
 {
  bbc_move(x,y+i);
  bbc_draw(x+w,y+i);
 }

 for(i=0;i<4;i+=deltax)
 {
  bbc_move(x+i,y);
  bbc_draw(x+i,y-h);
 }

 wimp_setcolour(1);

 for(i=0;i<4;i+=deltay)
 {
  bbc_move(x,y-h+i);
  bbc_draw(x+w,y-h+i);
 }

 for(i=0;i<4;i+=deltax)
 {
  bbc_move(x+w-i,y);
  bbc_draw(x+w-i,y-h);
 }
}



#define FONTCODE  26
#define COLCODE   18
#define COLCODE2  19

static int deskfonthandle;
static int desklead;
static int deskheight;
static int cwidth[256];


static void deskfontstart(void)
{
 os_regset  rx;
 os_error * err;
 int        i;
 font_info fi;
 char       string[4];
 font_string fs;

 if(wimp_version<350)
 {
  deskfonthandle=0;
 }
 else
 {
  rx.r[0]=8;
  err=os_swix(Wimp_ReadSysInfo,&rx);

  if(!err) 
  {
   deskfonthandle=rx.r[0];
   memset(cwidth,0,sizeof(int)*256);
   desklead=deskheight=0;

   for(i='a';i<='z';i++)
   {
    string[0]=FONTCODE;
    string[1]=deskfonthandle;
    string[2]=i;
    string[3]=0;
 
    font_stringbbox(string,&fi);

    if(fi.maxy>desklead) desklead=fi.maxy;
    if((fi.maxy-fi.miny)>deskheight) deskheight=(fi.maxy-fi.miny);

    fs.s=string;
    fs.x=CHWIDTH2*400;
    fs.y=CHWIDTH2*400;
    fs.split=-1;
    fs.term=4;

    font_strwidth(&fs);

    cwidth[i]=fs.x;
   }
  }
  else deskfonthandle=0;
 }
}


static void getcx(int c)
{
 os_error * err;
 char       string[4];
 font_string fs;

 string[0]=FONTCODE;
 string[1]=deskfonthandle;
 string[2]=c;
 string[3]=0;

 fs.s=string;
 fs.x=CHWIDTH2*400;
 fs.y=CHWIDTH2*400;
 fs.split=-1;
 fs.term=4;

 err=font_strwidth(&fs);
 if(!err) cwidth[c]=fs.x;
}





void redrawg(wimp_redrawstr * redrawstr)
{
 int bx;
 int by;
 int gx0;
 int gx1;
 int gy1;
 int gy0;
 int y;
 int x;
 int i;
 int j;
 int x0;
 int x1;
 int y0;
 int y1;
 int c;
 char string[64];
 int  fcol;
 int  bcol;
 int  shift;

 deskfontstart();



 bx=redrawstr->box.x0-redrawstr->scx;
 by=redrawstr->box.y1-redrawstr->scy;

 x0=redrawstr->box.x0;
 x1=redrawstr->box.x1;
 y0=redrawstr->box.y0;
 y1=redrawstr->box.y1;


 gx0=((redrawstr->g.x0-bx)/meshx)*meshx+bx;
 gy1=((redrawstr->g.y1-by)/meshy)*meshy+by;
 gx1=redrawstr->g.x1;
 gy0=redrawstr->g.y0-meshy;


 j=(-(gy1-by))/meshy;

 for(y=gy1;y>=(redrawstr->g.y0-meshy);j++,y-=meshy)    
 {
  i=(gx0-bx)/meshx;

  for(x=gx0;x<redrawstr->g.x1;i++,x+=meshx)
  {
   if(i<maxx && j<maxy)
   {
    if((gridstate[i][j] & STMASK)==BLOCK)
    {
     shadedsquare(x,y);
    }
    else
    if((gridstate[i][j] & STMASK)==HILITE)
    {
     wimp_setcolour(bcol=zonecolour);
     bbc_rectanglefill(x,y,meshx,-meshy);
    }
    else
    if(i==cursx && j==cursy)
    {
     wimp_setcolour(bcol=cursorcolour);
     bbc_rectanglefill(x,y,meshx,-meshy);
    }
    else
    if(reflag)
    {
     wimp_setcolour(bcol=WHITE);
     bbc_rectanglefill(x,y,meshx,-meshy);
    }
    else
    {
     bcol=WHITE;
    }

    if((gridstate[i][j] & STMASK)!=BLOCK)
    {
     if(deskfonthandle)
     {
      fcol=BLACK;

      bcol=vdupal.c[bcol].word;
      fcol=vdupal.c[fcol].word;

      c=griddata[i][j];
      if(c!=32)
      {
       string[0]=FONTCODE;
       string[1]=deskfonthandle;
       string[2]=COLCODE2;
       string[3]=bcol>>8;
       string[4]=bcol>>16;
       string[5]=bcol>>24;
       string[6]=fcol>>8;
       string[7]=fcol>>16;
       string[8]=fcol>>24;
       string[9]=14;

       /* find difference between mesh width and char width */

       if(!cwidth[c]) getcx(c);


       shift=meshx*400-cwidth[c];
       shift/=2;

       string[10]=9; /* HM */
       string[11]=shift;
       string[12]=shift>>8;
       string[13]=shift>>16;

       shift=meshy*400-deskheight;
       shift/=2;
       shift+=desklead;
       shift/=400;

       string[14]=c;
       string[15]=0;

       font_paint(string,font_ABS|font_OSCOORDS,x,y-shift);
      }
     }
     else
     {
      wimp_setcolour(BLACK);
      bbc_move(x+meshx/2-8,y-meshy/2+12);
      bbc_vdu(griddata[i][j]); 
     }

     if(gridstate[i][j] & (BLOCKX|BLOCKY))
     {
      wimp_setcolour(BLACK);

      if(gridstate[i][j] & BLOCKY)
      {
       bbc_move(x,y-deltay);
       bbc_draw(x+meshx,y-deltay);
       bbc_move(x,y-2*deltay);
       bbc_draw(x+meshx,y-2*deltay);
      }

      if(gridstate[i][j] & BLOCKX)
      {
       bbc_move(x+deltax,y);
       bbc_draw(x+deltax,y-meshy);
       bbc_move(x+2*deltax,y);
       bbc_draw(x+2*deltax,y-meshy);
      }
     }
    }
   }
  }
 }

 wimp_setcolour(BLACK);

 for(y=gy1;y>=gy0;y-=meshy)
 {
  bbc_move(x0,y);
  bbc_draw(x1,y);
 }

 for(x=gx0;x<gx1;x+=meshx)
 {
  bbc_move(x,y1);
  bbc_draw(x,y0);
 }

}



void gridredraw(wimp_redrawstr * redrawstr,int more)
{
 while(more)
 { 
  redrawg(redrawstr);
  wimp_get_rectangle(redrawstr,&more);
 }
}





void xrepaint(int x0,int y0,int x1,int y1)  /*repaints area using char vars*/
{ 
 wimp_redrawstr redrawstr;
 int            more;

 x0=x0*meshx;
 y0=-(y0*meshy);
 x1=x1*meshx;
 y1=-(y1*meshy);


 redrawstr.w=whandle[CROSS2];
 redrawstr.box.x0=x0;
 redrawstr.box.y0=y0-meshy;  
 redrawstr.box.x1=x1+meshx;
 redrawstr.box.y1=y1; 

 reflag=1;
 wimp_update_wind(&redrawstr,&more);
 gridredraw(&redrawstr,more);
 reflag=0;
}


void refreshgrid(void)
{
 refreshwindow(whandle[CROSS2]);
}



void kill_cursor(void)
{
 int xc,yc;

 xc=cursx;
 yc=cursy;
 cursx=cursy=-1;
 xrepaint(xc,yc,xc,yc);
 cursx=xc;
 cursy=yc;
}



void refreshcursor(void)
{
 xrepaint(cursx,cursy,cursx,cursy);
}






void hilitezone(void)
{
 int xc0;
 int yc0;
 int xc1;
 int yc1;
 int x;
 int y;

 if(zx0<zx1)
 {
  xc0=zx0;
  xc1=zx1;
 }
 else
 {
  xc0=zx1;
  xc1=zx0;
 }

 if(zy0>zy1)
 {
  yc0=zy0;
  yc1=zy1;
 }
 else
 {
  yc0=zy1;
  yc1=zy0;
 }


 for(y=yc1;y<=yc0;y++)
  for(x=xc0;x<=xc1;x++)
  {
   if((gridstate[x][y] & STMASK)!=BLOCK)
   {
    gridstate[x][y]&=~STMASK;
    gridstate[x][y]|=HILITE;
   }
  }
}







void clearhilite(void)
{
 int xc0;
 int yc0;
 int xc1;
 int yc1;
 int x;
 int y;

 if(zx0<zx1)
 {
  xc0=zx0;
  xc1=zx1;
 }
 else
 {
  xc0=zx1;
  xc1=zx0;
 }

 if(zy0>zy1)
 {
  yc0=zy0;
  yc1=zy1;
 }
 else
 {
  yc0=zy1;
  yc1=zy0;
 }

 if(yc1>=0 && yc0<maxy && xc0>=0 && xc1<maxx)
  for(y=yc1;y<=yc0;y++)
   for(x=xc0;x<=xc1;x++)
   {
    if((gridstate[x][y] & STMASK)!=BLOCK)
    {
     gridstate[x][y]&=~STMASK;
     gridstate[x][y]|=CHARST;
    }
   }
}




void removezone(void)
{
 clearhilite();
 zx0=zx1=zy0=zy1=-1;
 wzone();
}




void kill_zone(void)
{
 int xc0,yc0,xc1,yc1;

 if(zx0<zx1)
 {
  xc0=zx0;
  xc1=zx1;
 }
 else
 {
  xc0=zx1;
  xc1=zx0;
 }

 if(zy0>zy1)
 {
  yc0=zy0;
  yc1=zy1;
 }
 else
 {
  yc0=zy1;
  yc1=zy0;
 }

 removezone();
 blanksolutions();
 xrepaint(xc0,yc0,xc1,yc1);
}




void refresh_zone(void)
{
 int xc0,yc0,xc1,yc1;

 if(zx0<zx1)
 {
  xc0=zx0;
  xc1=zx1;
 }
 else
 {
  xc0=zx1;
  xc1=zx0;
 }


 if(zy0>zy1)
 {
  yc0=zy0;
  yc1=zy1;
 }
 else
 {
  yc0=zy1;
  yc1=zy0;
 }

 reflag=1;
 xrepaint(xc0,yc0,xc1,yc1);
 reflag=0;
}









/*****************************************************************************/

void newredraws(wimp_redrawstr * redrawstr)
{
 int      bx;
 int      by;
 int      w;
 int      h;
 buffer * dbuffer;
 int      i;
 int      j;
 int      gy1;
 char   * p;
 char   * q;
 char   * r;
 int      y;
 char     string[256];
 int      zx;
 int      zy;
 int      n;
 int      cx;
 int      cy;
 int      shift;
 int      xshift;
 int      c;
 int      fcol;
 int      bcol;

 bx=redrawstr->box.x0-redrawstr->scx;
 by=redrawstr->box.y1-redrawstr->scy;

 w=cluex1-cluex0+1;
 h=cluey0-cluey1+1;

 createbuffer(&dbuffer);
 setsizebuffer(&dbuffer,w*h);
 p=dbuffer->buff;

 bcol=vdupal.c[WHITE].word;
 fcol=vdupal.c[BLACK].word;

 if(solwidth<=1 && h>1) {w=h;h=1;}

 gy1=((redrawstr->g.y1-by)/solheight)*solheight+by;

 j=(-(gy1-by))/solheight;

 for(y=gy1;y>=(redrawstr->g.y0-solheight) && j<nsol;j++,y-=solheight)    
 {
  memset(p,0,w*h);

  for(i=0;i<solwidth;i++)
  {
   q=p+(cluestr[i].x-cluex0)+w*(cluestr[i].y-cluey1);
   r=swordn(*((int*)(sbuffer->buff+(j*solwidth+i)*sizeof(int))));

   if(cluestr[i].down && (solwidth>1)) 
   {
    while(*r)
    {
     *q=*r++;
     q+=w;
    }
   }
   else
   {
    while(*r)
    {
     *q++=*r++;
    }
   }
  }



  for(zy=0;zy<h;zy++)
  {
   n=0;
   xshift=0;

   string[n++]=FONTCODE;
   string[n++]=deskfonthandle;
   string[n++]=COLCODE2;
   string[n++]=bcol>>8;
   string[n++]=bcol>>16;
   string[n++]=bcol>>24;
   string[n++]=fcol>>8;
   string[n++]=fcol>>16;
   string[n++]=fcol>>24;
   string[n++]=14;

   for(zx=0;zx<w;zx++)
   {
    c=*(p+zy*w+zx);
    if(c && c!=32)
    {
     if(!cwidth[c]) getcx(c);
     shift=CHWIDTH2*400-cwidth[c];

     shift/=2;

     xshift+=shift;
     if(xshift)
     {
      string[n++]=9; /* HM */
      string[n++]=xshift;
      string[n++]=xshift>>8;
      string[n++]=xshift>>16;
     }

     string[n++]=c;

     xshift=shift;
    }
    else xshift+=CHWIDTH2*400;
   }
   string[n]=0;

   cx=bx+HORIZMARGIN+HORIZSHIFT;
   cy=y-VERTMARGIN-VERTSHIFT-zy*CHHEIGHT;

   shift=CHHEIGHT*400-deskheight;
   shift/=2;
   shift+=desklead;
   shift/=400;

   font_paint(string,font_ABS|font_OSCOORDS,cx,cy-shift);
  }
 }
 deletebuffer(&dbuffer);
}





/* redraw just single clues */

void sxredraw(wimp_redrawstr * redrawstr)
{
 int bx;
 int by;
 int gy1;
 int y;
 int j;
 char * p;
 int cx;
 int cy;

 bx=redrawstr->box.x0-redrawstr->scx;
 by=redrawstr->box.y1-redrawstr->scy;

 gy1=((redrawstr->g.y1-by)/solheight)*solheight+by;

 j=(-(gy1-by))/solheight;

 for(y=gy1;y>=(redrawstr->g.y0-solheight) && j<nsol;j++,y-=solheight)    
 {
  cx=bx+HORIZMARGIN+HORIZSHIFT+(cluestr[0].x-zx0)*CHWIDTH;
  cy=y-VERTMARGIN-/*VERTSHIFT- */(cluestr[0].y-zy1)*CHHEIGHT;

  p=swordn(*((int*)(sbuffer->buff+(j*solwidth)*sizeof(int))));

  stringat(cx,cy,p,textcolour,solheight);
 }
}





void redraws(wimp_redrawstr * redrawstr)
{
 int bx;
 int by;
 int gy1;
 int y;
 int j;
 int i;
 int xwidth;
 int xw;

 bx=redrawstr->box.x0-redrawstr->scx;
 by=redrawstr->box.y1-redrawstr->scy;

 xw=redrawstr->box.x1-redrawstr->box.x0;
 if(xw>solxwidth) xwidth=xw;
 else             xwidth=solxwidth;

 gy1=((redrawstr->g.y1-by)/solheight)*solheight+by;

 j=(-(gy1-by))/solheight;


 for(y=gy1;y>=(redrawstr->g.y0-solheight) && j<nsol;j++,y-=solheight)    
 {
  wimp_setcolour(outercolour);
  bbc_rectanglefill(bx+HORIZMARGIN,y-VERTMARGIN,
               /*     (zx1-zx0+1)*CHWIDTH+2*HORIZSHIFT, */
                    xwidth-2*HORIZMARGIN,
                /*   -(zy0-zy1+1)*CHHEIGHT-2*VERTSHIFT); */
                     -solheight+2*VERTMARGIN);

  for(i=0;i<solwidth;i++)
  {
   wimp_setcolour(innercolour);

   bbc_rectanglefill(bx+HORIZMARGIN+HORIZSHIFT+(cluestr[i].x-zx0)*CHWIDTH,
                     y-VERTMARGIN-VERTSHIFT-(cluestr[i].y-zy1)*CHHEIGHT,
   (cluestr[i].down && (solwidth>1))?CHWIDTH:cluestr[i].len*CHWIDTH,
    -((cluestr[i].down && (solwidth>1))?cluestr[i].len*CHHEIGHT:CHHEIGHT));


   bbc_move(bx+HORIZMARGIN+HORIZSHIFT+(cluestr[i].x-zx0)*CHWIDTH,
             y-VERTMARGIN-VERTSHIFT-(cluestr[i].y-zy1)*CHHEIGHT);


  if(cluestr[i].down && (solwidth>1)) bbc_vduq(23,16,0x48,0,0,0,0,0,0,0);
  else                                bbc_vduq(23,16,0x40,0,0,0,0,0,0,0);


   wimp_setcolour(textcolour);

   bbc_stringprint(swordn(
         *((int*)(sbuffer->buff+(j*solwidth+i)*sizeof(int)))
                         )
                  );

  }
 }

 bbc_vduq(23,16,0x40,0,0,0,0,0,0,0); 
}




void refreshsols(void)
{
 refreshwindow(whandle[CROSS3]);
}



void solredraw(wimp_redrawstr * redrawstr,int more)
{
 if(solwidth>1)
 {
  deskfontstart();
  while(more)
  { 
   if(deskfonthandle) newredraws(redrawstr);
   else               redraws(redrawstr);
   wimp_get_rectangle(redrawstr,&more);
  }
 }
 else
 {
  wimpfontstart();
  while(more)
  { 
   sxredraw(redrawstr);
   wimp_get_rectangle(redrawstr,&more);
  }
  wimpfontend();
 }
}







void setsolextent(void)
{
 int xtent;
 int ytent;

 getw(whandle[CROSS3]);

 xtent=x1-x0;
 ytent=-(y0-y1);

 if((nsol*solheight)>ytent) ytent=(nsol*solheight);
 if(solxwidth>xtent) xtent=solxwidth;

 extent(whandle[CROSS3],0,-ytent,xtent,0);
}



void opensol(void)
{
 getw(whandle[CROSS3]);
 if(wflags & 0x10000) openatscroll(whandle[CROSS3],0,0);
}



void opengrid(int scx,int scy)
{
 openatscroll(whandle[CROSS2],scx,scy);
}



/*****************************************************************************/


void wzone(void)
{
 static int oldwidth;
        int width;

 if(zx0!=-1)
 {
  if(zx0==zx1) width=zy0-zy1;
  else         width=zx0-zx1;

  if(width<0)  width=-width;

  if(oldwidth!=width) writeiconf(whandle[CROSS],4,"%d",width+1);
 }
 else
 {
  writeicon(whandle[CROSS],4,"");
  width=-1;
 }

 oldwidth=width;
}



void wscale(void)
{
/* writeiconf(whandle[CROSS],4,"%dx%d",maxx,maxy); */
}




void setscale(void)
{
 int xtent,ytent;

 if(maxx<=16 && maxx>=8) meshx=EXT/maxx;
 else 
 if(maxx>16) meshx=EXT/16;
 else
 if(maxx<8)  meshx=EXT/8;

 if(maxy<=16 && maxy>=8) meshy=EXT/maxy;
 else 
 if(maxy>16) meshy=EXT/16;
 else
 if(maxy<8)  meshy=EXT/8;

 wscale();

 if(maxx*meshx>EXT) xtent=maxx*meshx; else xtent=EXT;
 if(maxy*meshy>EXT) ytent=maxy*meshy; else ytent=EXT;

 extent(whandle[CROSS2],0,-ytent,xtent,0);

 xext=xtent;
 yext=-ytent;
}





void cleargrid(void)
{
 int x,y;

 for(x=0;x<MAXX;x++)
   for(y=0;y<MAXY;y++)
   {
    griddata[x][y]=32;
    gridstate[x][y]&=~(STMASK|BLOCKX|BLOCKY);
    gridstate[x][y]|=CHARST;
   }
}






void cleartext(void)
{
 int x,y;

 for(x=0;x<MAXX;x++)
   for(y=0;y<MAXY;y++)
    if((gridstate[x][y] & STMASK)==CHARST) griddata[x][y]=32;
}




void setsize(int x,int y)
{
 if(x<MAXX) maxx=x;
 else       maxx=MAXX-1;

 if(y<MAXY) maxy=y;
 else       maxy=MAXY-1;

 setscale();
 removezone();
 blanksolutions();
 refreshgrid();
}



void clear_screen(void)
{
 cleargrid();
 removezone();
 blanksolutions();
 refreshgrid();
}



void clear_words(void)
{
 removezone();
 blanksolutions();
 cleartext();
 refreshgrid();
}



void reflecthoriz(void)
{
 int x;
 int y;
 int s;
 int o;

 removezone();
 blanksolutions();

 for(x=0;x<(maxx-1)/2;x++)
 {
  for(y=0;y<maxy;y++)
  {
   s=gridstate[x][y] &(BLOCKX);
   o=gridstate[maxx-1-x][maxy-1-y] & (BLOCKX);

   gridstate[maxx-1-x][y]=gridstate[x][y] & (~(BLOCKX));
   gridstate[maxx-1-x][y]=gridstate[maxx-1-x][y] | o;

   gridstate[maxx-x][y]=(gridstate[maxx-x][y] & (~(BLOCKX))) | s;
  }
 }

 refreshgrid();
}






void reflectvert(void)
{
 int x;
 int y;
 int s;
 int o;

 removezone();
 blanksolutions();

 for(y=0;y<(maxy-1)/2;y++)
 {
  for(x=0;x<maxx;x++)
  {
   s=gridstate[x][y] &(BLOCKY);
   o=gridstate[maxx-1-x][maxy-1-y] & (BLOCKY);

   gridstate[x][maxy-1-y]=gridstate[x][y] & (~(BLOCKY));
   gridstate[x][maxy-1-y]=gridstate[x][maxy-1-y] | o;

   gridstate[x][maxy-y]=(gridstate[x][maxy-y] & (~(BLOCKY))) | s;
  }
 }
 refreshgrid();
}




/* reflect in / diag */

void reflectdiag1(void)
{
 int x;
 int y;
 int xlimit;
 int s;
 int o;

 removezone();
 blanksolutions();

 for(y=0;y<maxy;y++)
 {
  xlimit=(maxx*(maxy-y))/maxy;

  for(x=0;x<xlimit;x++)
  {
   s=gridstate[x][y] & (BLOCKX|BLOCKY);
   o=gridstate[maxx-1-x][maxy-1-y] & (BLOCKX|BLOCKY);

   gridstate[maxx-1-x][maxy-1-y]=gridstate[x][y] & (~(BLOCKX|BLOCKY));
   gridstate[maxx-1-x][maxy-1-y]=gridstate[maxx-1-x][maxy-1-y] | o;

   gridstate[maxx-1-x][maxy-y]=
                (gridstate[maxx-1-x][maxy-y] & (~(BLOCKY))) | (s & BLOCKY);

   gridstate[maxx-x][maxy-1-y]=
                (gridstate[maxx-x][maxy-1-y] & (~(BLOCKX))) | (s & BLOCKX);
  }
 }

 refreshgrid();
}



/* reflect in \ diag */

void reflectdiag2(void)
{
 int x;
 int y;
 int xlimit;
 int s;
 int o;

 removezone();
 blanksolutions();

 for(y=0;y<maxy;y++)
 {
  xlimit=(maxx*y)/maxy;

  for(x=maxx-1;x>=xlimit;x--)
  {
   s=gridstate[x][y] & (BLOCKX|BLOCKY);
   o=gridstate[maxx-1-x][maxy-1-y] & (BLOCKX|BLOCKY);

   gridstate[maxx-1-x][maxy-1-y]=gridstate[x][y] & (~(BLOCKX|BLOCKY));
   gridstate[maxx-1-x][maxy-1-y]=gridstate[maxx-1-x][maxy-1-y] | o;

   gridstate[maxx-1-x][maxy-y]=
                (gridstate[maxx-1-x][maxy-y] & (~(BLOCKY))) | (s & BLOCKY);

   gridstate[maxx-x][maxy-1-y]=
                (gridstate[maxx-x][maxy-1-y] & (~(BLOCKX))) | (s & BLOCKX);
  }
 }

 refreshgrid();
}






void update_cursor(void)
{
 lcursx=cursx;
 lcursy=cursy;
}




void removecursor(void)
{
 cursx=cursy=-1;
 update_cursor();
}





void cursor_left(void)
{
 int i;

 /* scan left until find good square */

 for(i=cursx-1;i>-1;i--)
    if((gridstate[i][cursy] & STMASK)!=BLOCK) break;

 if(i==-1) return;

 getw(whandle[CROSS2]);
 if(i*meshx<scx) opengrid(i*meshx,scy);

 kill_cursor();
 update_cursor();
 cursx=i;
 refreshcursor();
}







void cursor_right(void)
{
 int i;

 for(i=cursx+1;i<maxx;i++)
    if((gridstate[i][cursy] & STMASK)!=BLOCK) break;
 if(i==maxx) return;

 getw(whandle[CROSS2]);
 if((i*meshx)>(scx+EXT-meshx)) opengrid((i+1)*meshx-EXT,scy);

 kill_cursor();
 update_cursor();
 cursx=i;
 refreshcursor();
}








void cursor_up(void)
{
 int i;

 for(i=cursy-1;i>-1;i--)
    if((gridstate[cursx][i] & STMASK)!=BLOCK) break;
  if(i==-1) return;

 getw(whandle[CROSS2]);
 if(i*meshy<-scy) opengrid(scx,-i*meshy);

 kill_cursor();
 update_cursor();
 cursy=i;
 refreshcursor();
}





void cursor_down(void)
{
 int i;

 for(i=cursy+1;i<maxy;i++)
    if((gridstate[cursx][i] & STMASK)!=BLOCK) break;

 if(i==maxy) return;

 getw(whandle[CROSS2]);
 if((i*meshy)>=(-scy+EXT-meshy)) opengrid(scx,-(i+1)*meshy+EXT);

 kill_cursor();
 update_cursor();
 cursy=i;
 refreshcursor();
}





void shift_cursor(void)
{
 int right,down;

 right=((cursx+1)<maxx && 
        (gridstate[cursx+1][cursy] & STMASK)!=BLOCK &&
        !(gridstate[cursx+1][cursy] & BLOCKX)
       );

 down =((cursy+1)<maxy && 
        (gridstate[cursx][cursy+1] & STMASK)!=BLOCK &&
        !(gridstate[cursx][cursy+1] & BLOCKY)
       );

 getw(whandle[CROSS2]);

 if((cursx==(lcursx+1) && cursy==lcursy && right) || (right && !down))
 {
  update_cursor();
  cursx++;
  if((cursx*meshx)>(scx+EXT-meshx)) opengrid((cursx+1)*meshx-EXT,scy);
 }
 else
 if((cursy==(lcursy+1) && cursx==lcursx && down)  || (down  && !right))
 {
  update_cursor();
  cursy++;
  if((cursy*meshy)>=(-scy+EXT-meshy)) opengrid(scx,-(cursy+1)*meshy+EXT);
 }
 else 
  bbc_vdu(7);
}






void back_cursor(void)
{
 int left,up;

 left=((cursx-1)>-1 && (gridstate[cursx-1][cursy] & STMASK)!=BLOCK);
 up  =((cursy-1)>-1 && (gridstate[cursx][cursy-1] & STMASK)!=BLOCK);

 getw(whandle[CROSS2]);

 if((cursx==(lcursx-1) && cursy==lcursy && left) || (left && !up))
 {
  update_cursor();
  cursx--;
  if(cursx*meshx<scx) opengrid(cursx*meshx,scy);
 }
 else
 if((cursy==(lcursy-1) && cursx==lcursx && up) || (up && !left))
 {
  update_cursor();
  cursy--;
  if(cursy*meshy<-scy)  opengrid(scx,-cursy*meshy);
 }
 else 
  bbc_vdu(7);
}






int scroll_left(void)
{
 int tsc;
 getw(whandle[CROSS2]);
 tsc=scx;
 if(scx==0) return(0);
 opengrid(scx-meshx,scy);
 getw(whandle[CROSS2]);
 return(!(scx==tsc));
}






int scroll_right(void)
{
 int tsc;
 getw(whandle[CROSS2]);
 tsc=scx;
 if(scx==xext-EXT) return(0);
 opengrid(scx+meshx,scy);
 getw(whandle[CROSS2]);
 return(!(scx==tsc));
}







int scroll_up(void)
{
 int tsc;
 getw(whandle[CROSS2]);
 tsc=scy;
 if(scy==0) return(0);
 opengrid(scx,scy+meshy);
 getw(whandle[CROSS2]);
 return(!(scy==tsc));
}





int scroll_down(void)
{
 int tsc;
 getw(whandle[CROSS2]);
 tsc=scy;
 if(scy==yext+EXT) return(0);
 opengrid(scx,scy-meshy);
 return(!(scy==tsc));
}




/**************************************************************************/


int min3(int x1,int x2,int x3)
{
 if(x1<x2) x2=x1;
 if(x2<x3) x3=x2;
 if(x3<x1) x1=x3;
 return(x1);
}



int max3(int x1,int x2,int x3)
{
 if(x1>x2) x2=x1;
 if(x2>x3) x3=x2;
 if(x3>x1) x1=x3;
 return(x1);
}



void cross2zero(void)
{
 int x;
 int y;
 int ox; 
 int oy;

 int xmin;
 int xmax;
 int ymin;
 int ymax;


 getpointer();
 getw(whandle[CROSS2]);
 x=(mousex-x0+scx)/meshx;
 y=(-scy+y1-mousey-4)/meshy;

 if(x<0) x=0;
 if(x>=maxx) x=maxx-1;
 if(y<0) y=0;
 if(y>=maxy) y=maxy-1;

 if(x!=cursx || y!=cursy)
 {
  if(zx0==-1)
  {
   zx0=zx1=cursx;
   zy0=zy1=cursy;
  }

  if(zx1!=x || zy1!=y)
  {
   if(abs(zx0-x)>abs(zy0-y)) y=zy0;
   else                      x=zx0;

   if((gridstate[x][y] & STMASK)!=BLOCK)
   {
    ox=zx1;
    oy=zy1;
    clearhilite();
    zx1=x;
    zy1=y;
    hilitezone();

    wzone();

    if(oy==zy1)
    {
     if(zx1>zx0 && ox<zx1) xrepaint(ox,zy1,zx1,zy1);
     else
     if(zx1>zx0 && ox>zx1) xrepaint(zx1,zy1,ox,zy1);
     else
     if(zx1<zx0 && ox<zx1) xrepaint(ox,zy1,zx1,zy1);
     else
     if(zx1<zx0 && ox>zx1) xrepaint(zx1,zy1,ox,zy1);
    }
    else
    if(ox==zx1)
    {
     if(zy1>zy0 && oy<zy1) xrepaint(zx1,zy1,zx1,oy);
     else
     if(zy1>zy0 && oy>zy1) xrepaint(zx1,oy,zx1,zy1);
     else
     if(zy1<zy0 && oy<zy1) xrepaint(zx1,zy1,zx1,oy);     
     else
     if(zy1<zy0 && oy>zy1) xrepaint(zx1,oy,zx1,zy1);
    }
    else
    {
     xmin=min3(ox,zx0,zx1);
     ymin=min3(oy,zy0,zy1);
     xmax=max3(ox,zx0,zx1);
     ymax=max3(oy,zy0,zy1);

     xrepaint(xmin,ymax,xmax,ymin);
    }
   }
  }
 }
 else
 {
  if(zx0!=-1)
  {
   kill_zone();
  }
 }

 if(mousex>x1) scroll_right();
 if(mousex<x0) scroll_left();
 if(mousey<y0) scroll_down();
 if(mousey>y1) scroll_up();
}


/**************************************************************************/

/*

   menu          -> pop up menu
   select        -> home cursor
   adjust        -> toggle squares
                    if zone extend zone
   drag select   -> set up zone
   double select -> mark word

*/



void calczonesize(void)
{
 int x;
 int y;

 zx0=zx1=zy0=zy1=-1;

 for(x=0;x<maxx;x++)
  for(y=0;y<maxy;y++)
   if((gridstate[x][y] & STMASK)==HILITE)
   {
    if(zx0==-1)
    {
     zx0=zx1=x;
     zy0=zy1=y;
    }
    else
    {
     if(x<zx0) zx0=x;
     if(x>zx1) zx1=x;
     if(y<zy1) zy1=y;
     if(y>zy0) zy0=y;
    }
   }
}



void toggleblock(int x,int y)
{
 if((gridstate[x][y] & STMASK)==BLOCK)
 {
  griddata[x][y]=32;
  gridstate[x][y]&=~(STMASK|BLOCKX|BLOCKY);
  gridstate[x][y]|=CHARST;
 }
 else
 {
  gridstate[x][y]&=~STMASK;

  if(isshift) gridstate[x][y]^=BLOCKX;
  else
  if(isctrl)  gridstate[x][y]^=BLOCKY;
  else        gridstate[x][y]|=BLOCK;
 }
 xrepaint(x,y,x,y);
}


void cross2icon(void)
{
 int x,y;

 if(buttons==2)
 {
  popmain();
  kill_zone();
 }
 else
 {
  getw(whandle[CROSS2]);
  x=(mousex-x0+scx)/meshx;
  y=(-scy+y1-mousey-4)/meshy;

  if(buttons==0x1)                    /* adjust click */
  {
   if(zx0!=-1)
   {
    if((gridstate[x][y] & STMASK)!=BLOCK)
    {
     if((gridstate[x][y] & STMASK)==HILITE)
     {
      gridstate[x][y]&=~STMASK;
      gridstate[x][y]|=CHARST;
     }
     else
     {
      gridstate[x][y]&=~STMASK;
      gridstate[x][y]|=HILITE;
     }
     xrepaint(x,y,x,y);
     calczonesize();
     blanksolutions();
    }
   }
   else
   {
    toggleblock(x,y);

  /*  if(symterry & SLR)    toggleblock(maxx-1-x,y);
    if(symterry & SUD)    toggleblock(x,maxy-1-y);
    if(symterry & STLBR)  toggleblock(maxx-1-x,maxy-1-y); */

   }
  }
  else
  if(buttons==0x4)                  /* select click - home cursor */
  {
   findcaret();
   if(zx0!=-1) kill_zone();

   if((gridstate[x][y] & STMASK)==BLOCK) bbc_vdu(7);
   else
   {
    if(/* chandle==whandle[CROSS2] && */ cursx!=-1 && cursy!=-1) kill_cursor();
    cursx=x;
    cursy=y;
    update_cursor();
    setfocus(whandle[CROSS2]);
    refreshcursor();
   }
  }
  else
  if(buttons==0x40)                   /* select drag - start zone */
  {
   wimp_dragstr drg;

   getw(whandle[CROSS2]);

   drg.window=whandle[CROSS2];
   drg.type=7;
   drg.box.x0=mousex;
   drg.box.y0=mousey;
   drg.box.x1=mousex;
   drg.box.y1=mousey;
   drg.parent.x0=x0-2*deltax;
   drg.parent.y0=y0-2*deltay;
   drg.parent.x1=x1+2*deltax;
   drg.parent.y1=y1+2*deltay;

   wimp_drag_box(&drg);

   startdrag(ZONEDRAG,whandle[CROSS2]);
  }
 }
}





void cross3icon(void)
{
 int    x;
 int    y;

 if(buttons==2)
 {
  popmain();
  kill_zone();
 }
 else
 {
  getpointer();
  getw(whandle[CROSS3]);
  x=(mousex-x0+scx)/CHWIDTH;
  y=(-scy+y1-mousey-8)/solheight;

  if(buttons==4 && zx0!=-1)
  {
   if(y>=nsol) return;
   writesolution(y);
   refresh_zone();
  }
 }
}



void cross2key(int * key)
{
 int ch=*key;

 switch(ch)
 {
     case 0x181: 
                reflectvert();
                break;

     case 0x182:
                reflecthoriz();
                break;

     case 0x183:
                reflectdiag1();
                break;

     case 0x184:
                reflectdiag2();
                break;

     case 0x18C:
                cursor_left();
                break;

     case 0x18D:
                cursor_right();
                break;

     case 0x18E:
                cursor_down();
                break;

     case 0x18F:
                cursor_up();
                break;

     case 0x19D:
                scroll_right();
                break;

     case 0x19C:
                scroll_left();
                break;

     case 0x19E:
                scroll_down();
                break;

     case 0x19F:
                scroll_up();
                break;

     case   0x8:
     case  0x7F:
                griddata[cursx][cursy]=32;
                kill_cursor();
                back_cursor();
                refreshcursor();
                break;

        default:
                if(ch>255) return;

                ch=tolower(ch);
    /*          if(ch!=32 && (ch<'a' || ch >'z') && ch!='*') return; */
                griddata[cursx][cursy]=ch;
                kill_cursor();
                shift_cursor();
                refreshcursor();
                break;
 }
 *key=-1;
}




/**************************************************************************/


#define SCHUNK 0x100


void clearsolutions(void)
{
 if(nsol) deletebuffer(&sbuffer);
 nsol=maxsol=0;
}


void addsolution(int dcdata,int word)
{
 if(word==(solwidth-1))   /* starting a new solution */
 {
  if(nsol==maxsol)
  {
   if(!maxsol) createbuffer(&sbuffer);
   maxsol=setsizebuffer(&sbuffer,(maxsol+SCHUNK)*solwidth*sizeof(int))/
                                                    (solwidth*sizeof(int));
  }
  if(nsol<maxsol) nsol++;
 }

 if(maxsol)
  *((int*)(sbuffer->buff+((nsol-1)*solwidth+word)*sizeof(int)))=dcdata;
}



void fillinstring(int clue,char * string)
{
 int    x;
 int    y;
 int    len;

 len=cluestr[clue].len;
 x=cluestr[clue].x;
 y=cluestr[clue].y;

 if(cluestr[clue].down)
 {
  while(len--) griddata[x][y++]=*string++;
 }
 else
 {
  while(len--) griddata[x++][y]=*string++;
 }
}


void gridgetstring(int clue,char * string)
{
 int    x;
 int    y;
 int    len;

 len=cluestr[clue].len;
 x=cluestr[clue].x;
 y=cluestr[clue].y;

 if(cluestr[clue].down)
 {
  while(len--) *string++=griddata[x][y++];
 }
 else
 {
  while(len--) *string++=griddata[x++][y];
 }

 *string=0;
}




/* copies the s'th solution into the grid */

void writesolution(int s)
{
 int    n;
 int    x;
 int    y;
 int    len;
 char * p;

 for(n=0;n<solwidth;n++)
 {
  p=swordn(
           *((int*)(sbuffer->buff+(s*solwidth+n)*sizeof(int)))
          );

  len=cluestr[n].len;
  x=cluestr[n].x;
  y=cluestr[n].y;

  if(cluestr[n].down)
  {
   while(len--) griddata[x][y++]=*p++;
  }
  else
  {
   while(len--) griddata[x++][y]=*p++;
  }
 }

 refresh_zone();
}



/* problem is to scan zone area, and block it out into clues */
/* xc0<xc1, yc1<yc0, inclusive coords                        */


void setupcluesold(void)
{
 int xc0;
 int yc0;
 int xc1;
 int yc1;
 int i;
 int j;
 int x;
 int y;

 if(zx0==-1) return;

 if(zx0<zx1)
 {
  xc0=zx0;
  xc1=zx1;
 }
 else
 {
  xc0=zx1;
  xc1=zx0;
 }

 if(zy0>zy1)
 {
  yc0=zy0;
  yc1=zy1;
 }
 else
 {
  yc0=zy1;
  yc1=zy0;
 }

 cluex0=xc0;
 cluex1=xc1;
 cluey0=yc0;
 cluey1=yc1;


 solwidth=0;

 for(x=xc0;x<=xc1;x++)
  for(y=yc1;y<=yc0;y++)
   if((gridstate[x][y] & STMASK)!=HILITE)
   {
    gridstate[x][y]|=(XMASK+YMASK);
   }
   else
   {
    gridstate[x][y]&=~(XMASK+YMASK);
   }


 for(y=yc1;y<=yc0;y++)
 {
  for(x=xc0;x<=xc1;x++)
  {
   if((gridstate[x][y] & STMASK)==HILITE)
   {
    if(((!(gridstate[x][y] & XMASK)) && 
        (x<(xc1)) && 
        (!(gridstate[x+1][y] & XMASK))))
    {                                       /* x clue */
     cluestr[solwidth].x=x;
     cluestr[solwidth].y=y;
     cluestr[solwidth].down=0;
     j=0;

     for(i=x;i<=xc1;i++) 
     {
      gridstate[i][y]|=XMASK;
      if((gridstate[i][y] & STMASK)!=HILITE) break;
    /*  cluestr[solwidth].string[j++]=griddata[i][y]; */
      j++;
     }

     cluestr[solwidth].len=j;
  /*   cluestr[solwidth].string[j]=0; */

     solwidth++;
    }


    if(((!(gridstate[x][y] & YMASK)) && 
        (y<(yc0)) && 
        (!(gridstate[x][y+1] & YMASK))))
    {                                      /* y clue */
     cluestr[solwidth].x=x;
     cluestr[solwidth].y=y;
     cluestr[solwidth].down=1;
     j=0;

     for(i=y;i<=yc0;i++)
     {
      gridstate[x][i]|=YMASK;
      if((gridstate[x][i] & STMASK)!=HILITE) break;
   /*  cluestr[solwidth].string[j++]=griddata[x][i]; */
      j++;
     }

     cluestr[solwidth].len=j;
   /*  cluestr[solwidth].string[j]=0; */

     solwidth++;
    }
   }
   if(solwidth>=MAXCLUE) break;
  }
  if(solwidth>=MAXCLUE) break;
 }

 solxwidth=(xc1-xc0+1)*CHWIDTH2+2*(HORIZMARGIN+HORIZSHIFT);

 if(solwidth<=1)
 {
  solheight=CHHEIGHT+2*(VERTMARGIN /* +VERTSHIFT */ );
 }
 else
 {
  solheight=(yc0-yc1+1)*CHHEIGHT+2*(VERTMARGIN+VERTSHIFT);
 }
}



static void setupclues(void)
{
 int xc0;
 int yc0;
 int xc1;
 int yc1;
 int i;
 int j;
 int x;
 int y;
 int finished;

 if(zx0==-1) return;

 if(zx0<zx1)
 {
  xc0=zx0;
  xc1=zx1;
 }
 else
 {
  xc0=zx1;
  xc1=zx0;
 }

 if(zy0>zy1)
 {
  yc0=zy0;
  yc1=zy1;
 }
 else
 {
  yc0=zy1;
  yc1=zy0;
 }

 cluex0=xc0;
 cluex1=xc1;
 cluey0=yc0;
 cluey1=yc1;


 solwidth=0;

 for(x=xc0;x<=xc1;x++)
 {
  for(y=yc1;y<=yc0;y++)
  {
   if((gridstate[x][y] & STMASK)!=HILITE)
   {
    gridstate[x][y]|=(XMASK+YMASK);
   }
   else
   {
    gridstate[x][y]&=~(XMASK+YMASK);
   }
  }
 }

 for(y=yc1;y<=yc0;y++)
 {
  for(x=xc0;x<=xc1;x++)
  {
   if((gridstate[x][y] & (XMASK |YMASK))!=(XMASK |YMASK))
   {
    if((!(gridstate[x][y] & XMASK)) && 
       (x<(xc1)) && 
       (!(gridstate[x+1][y] & XMASK)) &&
       (!(gridstate[x+1][y] & BLOCKX)))
    {                                       /* x clue */
     cluestr[solwidth].x=x;
     cluestr[solwidth].y=y;
     cluestr[solwidth].down=0;
     j=0;

     for(i=x;i<=xc1;i++) 
     {
      finished=(gridstate[i][y] & XMASK);
      gridstate[i][y]|=XMASK;
      if(finished) break;
      j++;
      if(i<xc1 && (gridstate[i+1][y] & BLOCKX)) break;
     }

     cluestr[solwidth].len=(char)j;

     solwidth++;
    }


    if((!(gridstate[x][y] & YMASK)) && 
       (y<(yc0)) && 
       (!(gridstate[x][y+1] & YMASK)) &&
       (!(gridstate[x][y+1] & BLOCKY)))
    {                                      /* y clue */
     cluestr[solwidth].x=x;
     cluestr[solwidth].y=y;
     cluestr[solwidth].down=1;
     j=0;

     for(i=y;i<=yc0;i++)
     {
      finished=(gridstate[x][i] & YMASK);
      gridstate[x][i]|=YMASK;
      if(finished) break;
      j++;
      if(i<yc0 && (gridstate[x][i+1] & BLOCKY)) break;
     }

     cluestr[solwidth].len=(char)j;

     solwidth++;
    }
   }
   if(solwidth>=MAXCLUE) break;
  }
  if(solwidth>=MAXCLUE) break;
 }

 solxwidth=(xc1-xc0+1)*CHWIDTH2+2*(HORIZMARGIN+HORIZSHIFT);

 if(solwidth<=1)
 {
  solheight=CHHEIGHT+2*(VERTMARGIN /* +VERTSHIFT */ );
 }
 else
 {
  solheight=(yc0-yc1+1)*CHHEIGHT+2*(VERTMARGIN+VERTSHIFT);
 }
}




int nextclue(char * string,int clue)
{
 int i;
 int j;
 int x;
 int y;

 for(x=0;x<maxx;x++)
  for(y=0;y<maxy;y++)
   if((gridstate[x][y] & STMASK)==BLOCK)
   {
    gridstate[x][y]|=(XMASK+YMASK);
   }
   else
   {
    gridstate[x][y]&=~(XMASK+YMASK);
   }


 for(y=0;y<maxy;y++)
 {
  for(x=0;x<maxx;x++)
  {
   if((gridstate[x][y] & STMASK)!=BLOCK)
   {
    if(((!(gridstate[x][y] & XMASK)) && 
        (x<(maxx-1)) && 
        (!(gridstate[x+1][y] & (XMASK|BLOCKX)))))
    {                                       /* x clue */
     j=0;

     for(i=x;i<maxx;i++) 
     {
      if((gridstate[i][y] & BLOCKX) && i!=x) break;
      if((gridstate[i][y] & STMASK)==BLOCK) break;
      gridstate[i][y]|=XMASK;
      string[j++]=griddata[i][y];
     }

     string[j]=0;

     if(!clue--) return(1);
    }


    if(((!(gridstate[x][y] & YMASK)) && 
        (y<(maxy-1)) && 
        (!(gridstate[x][y+1] & (YMASK|BLOCKY)))))
    {                                      /* y clue */
     j=0;

     for(i=y;i<maxy;i++)
     {
      if((gridstate[x][i] & BLOCKY) && i!=y) break;
      if((gridstate[x][i] & STMASK)==BLOCK) break;
      gridstate[x][i]|=YMASK;
      string[j++]=griddata[x][i];
     }

     string[j]=0; 

     if(!clue--) return(1);
    }
   }
  }
 }

 return(0);
}








void blanksolutions(void)
{
 if(nsol)
 {
  clearsolutions(); 
  opensol();
  setsolextent();
  refreshsols();
 }
}


void solution(void)
{
 calczonesize();


 if(zx0==-1)
 {
  errorbox("Need marked word!");
  return;
 }

 clearsolutions();
 setupclues();




 if(solwidth) search(0);
 else         errorbox("Nothing to solve!");

 opensol();
 setsolextent();
 refreshsols();
}


void anagram(void)
{
 calczonesize();

 if(zx0==-1)
 {
  errorbox("Need marked word!");
  return;
 }

 clearsolutions();
 setupclues();

 if(solwidth!=1) errorbox("An anagram must be a single marked word!");
 else            anagramsearch();

 opensol();
 setsolextent();
 refreshsols();
}




void crossicon(void)
{
 if(buttons==2)
 {
  popmain();
  kill_zone();
 }
 else
 {
  switch(icon)
  {
   case 3:
          solution();
          break;

   case 2:
          anagram();
          break;
  }
 }
}



/**************************************************************************/


typedef struct
{
 char name[24];
 char  mark[8];
 char copy[64];
 char stuff[152];
 int  draftfill;
 int  saveupper;
 int  x;
 int  y;
} gheader;




int loadgridsub(char * filename)
{
 gheader gh;
 FILE  * fp;
 int     x;
 int     y;
 int     mark100;

 memset(&gh,0,sizeof(gh));

 fp=ropen(filename,"rb");
 if(fp)
 {
  trashfhdc();

  rread(&gh,sizeof(gheader),1,fp);

  mark100=(strcmp(gh.mark,"1.01")<0);

  maxx=gh.x;
  maxy=gh.y;
  saveupper=gh.saveupper;
  draftfill=gh.draftfill;

  readfhdc(fp);

  for(x=0;x<maxx;x++)
   rread(griddata[x],1,maxy,fp);

  for(x=0;x<maxx;x++)
   rread(gridstate[x],1,maxy,fp);

  for(x=0;x<maxx;x++)
  {
   for(y=0;y<maxy;y++)
   {
    if((gridstate[x][y] & STMASK)==HILITE)
     gridstate[x][y]&=~STMASK;

    if(mark100) gridstate[x][y]&=~(BLOCKX|BLOCKY);
   }
  }

  rclose(fp);

  mapfhdc();

  setscale();
  refreshgrid();
  removezone();
  blanksolutions();

  removecursor();

  return(1);
 }
 else
  return(0);
}


char loadname[256]="Grid";



int loadgrid(char * filename)
{
 int code;

 code=loadgridsub(filename);
 if(code) strcpy(loadname,filename);

 return(code);
}



void loaddefaultgrid(void)
{
 loadgridsub("<CrossStar$Path>.!Default");
}


int loadgridopen(char * filename)
{
 int code;

 code=loadgrid(filename);
 if(code) crossopenup();
 return(code);
}




int saveasgrid(char * filename)
{
 gheader gh;
 FILE  * fp;
 int     x;

 memset(&gh,0,sizeof(gh));

 strcpy(gh.name,"CrossStar Grid");
 strcpy(gh.mark,"1.01");
 strcpy(gh.copy,"(05-Jan-1996)");
 gh.x=maxx;
 gh.y=maxy;
 gh.saveupper=saveupper;
 gh.draftfill=draftfill;

 fp=ropen(filename,"wb");
 if(fp)
 {
  rwrite(&gh,sizeof(gheader),1,fp);

  writefhdc(fp);

  for(x=0;x<maxx;x++)
   rwrite(griddata[x],1,maxy,fp);

  for(x=0;x<maxx;x++)
   rwrite(gridstate[x],1,maxy,fp);

  savetypeclose(fp,filename);

  strcpy(loadname,filename);

  return(1);
 }
 else
  return(0);
}


void savedefaultgrid(void)
{
 saveftype=CROSSF;
 saveasgrid("<CrossStar$Path>.!Default");
}



/***************************************************************************/


void closecross(void)
{
 wimp_close_wind(whandle[CROSS3]);
 wimp_close_wind(whandle[CROSS2]);
 wimp_close_wind(whandle[CROSS]);
}


void crossopenup(void)
{
 wimp_wstate wst;
 static int  new;

 if(!new)
 {
  centerwindow(&wst,whandle[CROSS],0);
  new=1;
 }
 else
 {
  wimp_get_wind_state(whandle[CROSS],&wst);
  wst.o.behind=-1;
 }

 opencross(&wst.o);
}


int getparam(char ** p,int * val)
{
 int n;
 int c;

 while(1)
 {
  c=*((*p)++);

  if(c>='0' && c<='9') break;
  else
  if(c==0) return(0);
 }

 n=c-'0';

 while(1)
 {
  c=*((*p)++);

  if(c>='0' && c<='9') n=n*10+c-'0';
  else                 break;

 }

 *val=n;

 return(1);
}




void crossboot(void)
{
 char * p;
 int    r;
 int    g;
 int    b;

 createwindow(CROSS);
 createwindow(CROSS2);
 createwindow(CROSS3);

 cleargrid();

 removecursor();
 removezone();
 setscale();

 cursorcolour=BLUE;
 zonecolour=RED;
 innercolour=LIGHTGREY;
 outercolour=GREY;
 textcolour=BLACK;

 p=getenv("CrossStar$Options");

 if(p)
 {
  if(getparam(&p,&cursorcolour))
  {
   if(getparam(&p,&zonecolour))
   {
    if(getparam(&p,&innercolour))
    {
     if(getparam(&p,&outercolour))
     {
      if(getparam(&p,&textcolour))
      {
       if(getparam(&p,&iconfront))
       {
        if(getparam(&p,&iconback))
        {
         seti(whandle[CROSS],4,(iconback<<28)+(iconfront<<24),0xFF000000);

         getparam(&p,&r);
         getparam(&p,&g);
         if(getparam(&p,&b))
         {
          xdraftcolour=(b<<24)|(g<<16)|(r<<8);

          getparam(&p,&r);
          getparam(&p,&g);
          if(getparam(&p,&b))
          {
           xrealcolour=(b<<24)|(g<<16)|(r<<8);

           if(getparam(&p,&barthickness))
           {

           }
          }
         }
        }
       }
      }
     }
    }
   }
  }
 }

}

/*****************************************************************************/

buffer * dbuffer;

#define DX 0x2000
#define DY 0x2000


#define FY 0x1500
#define FX ((FY*6)/10)


#define CY 0xB00
#define CX ((CY*6)/10)

#define BCHUNK 0x5000


void checkbuff(Draw_diag * diag)
{
 if((dbuffer->len-diag->length)<BCHUNK) 
 {
  setsizebuffer(&dbuffer,dbuffer->len+BCHUNK);
 }
}




void makedrawfile(Draw_diag * diag)
{
 int x;
 int y;
 int offset;
 int clue;
 char string[8];
 int i;

 vecthickness(0);

 opendiag(diag,maxx*DX,maxy*DY);

 for(x=0;x<=maxx;x++)
 {
  vecmove(x*DX,0,diag);
  vecdraw(x*DX,maxy*DY,diag);
  checkbuff(diag);
 }

 for(y=0;y<=maxy;y++)
 {
  vecmove(0,y*DY,diag);
  vecdraw(maxx*DX,y*DY,diag);
  checkbuff(diag);
 }

 closedraw(diag);

 offset=diag->length;

 for(x=0;x<maxx;x++)
  for(y=0;y<maxy;y++)
  {
   if((gridstate[x][y] & STMASK)==BLOCK)
   {
    vecmove(x*DX,(maxy-1-y)*DY,diag);
    vecdraw((x+1)*DX,(maxy-1-y)*DY,diag);
    vecdraw((x+1)*DX,(maxy-y)*DY,diag);
    vecdraw(x*DX,(maxy-y)*DY,diag);
    vecdraw(x*DX,(maxy-1-y)*DY,diag);
    checkbuff(diag);
   }
  }

 if(diag->length!=offset) 
      vecfillcolour(draftfill?xdraftcolour:xrealcolour,diag,offset);

 closedraw(diag);


 /* now do clue numbers */

 for(x=0;x<maxx;x++)
  for(y=0;y<maxy;y++)
   if((gridstate[x][y] & STMASK)==BLOCK)
   {
    gridstate[x][y]|=(XMASK+YMASK);
   }
   else
   {
    gridstate[x][y]&=~(XMASK+YMASK);
   }

 clue=1;
 vectextsize(CX,CY,diag);

 for(y=0;y<maxy;y++)
 {
  for(x=0;x<maxx;x++)
  {
   if((gridstate[x][y] & STMASK)!=BLOCK)
   {
    if(((!(gridstate[x][y] & XMASK)) && 
        (x<(maxx-1)) && 
        (!(gridstate[x+1][y] & (XMASK|BLOCKX)))) ||
       ((!(gridstate[x][y] & YMASK)) && 
        (y<(maxy-1)) && 
        (!(gridstate[x][y+1] & (YMASK|BLOCKY))))
      )
    {
     sprintf(string,"%d",clue++);
     i=0;
     while(string[i])
     {
      vecsym(x*DX+CX*i+CX/6,(maxy-y)*DY-(6*CY)/10-CY/6,string[i],diag);
      i++;
     }

     for(i=x;i<maxx;i++) 
     {
      if((gridstate[i][y] & BLOCKX) && i!=x) break;
      if((gridstate[i][y] & STMASK)==BLOCK) break;
      gridstate[i][y]|=XMASK;
     }

     for(i=y;i<maxy;i++)
     {
      if((gridstate[x][i] & BLOCKY) && i!=y) break;
      if((gridstate[x][i] & STMASK)==BLOCK) break;
      gridstate[x][i]|=YMASK;
     }

     checkbuff(diag);
    }
   }
  }
 }


 /* now do text */

 vectextsize(FX,FY,diag);

 for(x=0;x<maxx;x++)
 {
  for(y=0;y<maxy;y++)
  {
   if((gridstate[x][y] & STMASK)!=BLOCK && griddata[x][y]!=32)
   {
    if(saveupper)
      vecsym(x*DX+(DX-FX-CX)/2+CX,(maxy-1-y)*DY+(DY-FY-CY)/2+(3*FY)/10,
                                         toupper(griddata[x][y]),diag);
      else
      vecsym(x*DX+(DX-FX-CX)/2+CX,(maxy-1-y)*DY+(DY-FY-CY)/2+(3*FY)/10,
                                                 griddata[x][y],diag);
    checkbuff(diag);
   }
  }
 }

 vecthickness(barthickness);

 for(x=0;x<maxx;x++)
 {
  for(y=0;y<maxy;y++)
  {
   if(gridstate[x][y] & BLOCKX)
   {
    vecmove(x*DX,(maxy-y)*DY,diag);
    vecdraw(x*DX,(maxy-y-1)*DY,diag);

    checkbuff(diag);
   }

   if(gridstate[x][y] & BLOCKY)
   {
    vecmove(x*DX,(maxy-y)*DY,diag);
    vecdraw((x+1)*DX,(maxy-y)*DY,diag);

    checkbuff(diag);
   }
  }
 }


 closediag(diag);
}



int saveasdraw(char * filename)
{
 FILE * fp;
 Draw_diag diag;

 fp=ropen(filename,"wb");
 if(fp)
 {
  createbuffer(&dbuffer);
  setsizebuffer(&dbuffer,BCHUNK);

  diag.data=dbuffer->buff;

  makedrawfile(&diag);
  rwrite(diag.data,diag.length,1,fp);
  savetypeclose(fp,filename);

  deletebuffer(&dbuffer);

  return(1);
 }
 else
  return(0);
}





int saveclues(char * filename)
{
 FILE * fp;
 int    i;
 int    x;
 int    y;
 int    clue;
 int    first;


 fp=ropen(filename,"wb");
 if(fp)
 {
  for(x=0;x<maxx;x++)
   for(y=0;y<maxy;y++)
    if((gridstate[x][y] & STMASK)==BLOCK)
    {
     gridstate[x][y]|=(XMASK+YMASK);
    }
    else
    {
     gridstate[x][y]&=~(XMASK+YMASK);
    }

  clue=0;
  first=1;

  for(y=0;y<maxy;y++)
  {
   for(x=0;x<maxx;x++)
   {
    if((gridstate[x][y] & STMASK)!=BLOCK)
    {
     if(((!(gridstate[x][y] & XMASK)) && 
         (x<(maxx-1)) && 
         (!(gridstate[x+1][y] & (XMASK|BLOCKX)))) ||

        ((!(gridstate[x][y] & YMASK)) && 
         (y<(maxy-1)) && 
         (!(gridstate[x][y+1] & (YMASK|BLOCKY))))
       )
     {
      clue++;

      for(i=x;i<maxx;i++) 
      {
       if(gridstate[i][y] & XMASK) break;
       if((gridstate[i][y] & BLOCKX) && i!=x) break;
       if((gridstate[i][y] & STMASK)==BLOCK) break;
       gridstate[i][y]|=XMASK;
      }

      if(i>(x+1))
      {
       if(first)
       {
        rfprintf(fp,"Clues across.\n\n");
        first=0;
       }

       rfprintf(fp,"%d. ",clue);

       for(i=x;i<maxx;i++)
       {
        if((gridstate[i][y] & BLOCKX) && i!=x) break;
        if((gridstate[i][y] & STMASK)==BLOCK) break;
        rputc(griddata[i][y],fp);
       }

       rputc('\n',fp);
      }

      for(i=y;i<maxy;i++)
      {
       if((gridstate[x][i] & BLOCKY) && i!=y) break;
       if((gridstate[x][i] & STMASK)==BLOCK) break;
       gridstate[x][i]|=YMASK;
      }
     }
    }
   }
  }

  if(!first) rputc('\n',fp);

  for(x=0;x<maxx;x++)
   for(y=0;y<maxy;y++)
    if((gridstate[x][y] & STMASK)==BLOCK)
    {
     gridstate[x][y]|=(XMASK+YMASK);
    }
    else
    {
     gridstate[x][y]&=~(XMASK+YMASK);
    }

  clue=0;
  first=1;

  for(y=0;y<maxy;y++)
  {
   for(x=0;x<maxx;x++)
   {
    if((gridstate[x][y] & STMASK)!=BLOCK)
    {
     if(((!(gridstate[x][y] & XMASK)) && 
         (x<(maxx-1)) && 
         (!(gridstate[x+1][y] & (XMASK|BLOCKX)))) ||

        ((!(gridstate[x][y] & YMASK)) && 
         (y<(maxy-1)) && 
         (!(gridstate[x][y+1] & (YMASK|BLOCKY))))
       )
     {
      clue++;

      for(i=x;i<maxx;i++) 
      {
       if((gridstate[i][y] & BLOCKX) && i!=x) break;
       if((gridstate[i][y] & STMASK)==BLOCK) break;
       gridstate[i][y]|=XMASK;
      }

      for(i=y;i<maxy;i++)
      {
       if(gridstate[x][i] & YMASK) break;
       if((gridstate[x][i] & BLOCKY) && i!=y) break;
       if((gridstate[x][i] & STMASK)==BLOCK) break;
       gridstate[x][i]|=YMASK;
      }


      if(i>(y+1))
      {
       if(first)
       {
        rfprintf(fp,"Clues down.\n\n");
        first=0;
       }

       rfprintf(fp,"%d. ",clue);

       for(i=y;i<maxy;i++)
       {
        if((gridstate[x][i] & BLOCKY) && i!=y) break;
        if((gridstate[x][i] & STMASK)==BLOCK) break;
        rputc(griddata[x][i],fp);
       }

       rputc('\n',fp);
      }

     }
    }
   }
  }
  savetypeclose(fp,filename);
  return(1);
 }
 else
  return(0);
}


